﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MoroMoro.Samples.ToDoList.Base.Domain.Builders
{
    /// <summary>
    /// エンティティビルダの基本クラスです。
    /// </summary>
    /// <remarks>
    /// <para>
    /// エンティティビルダは、エンティティの構築を行います。
    /// エンティティビルダの基本的な実装方法についてのガイドラインを次に示します。
    /// </para>
    /// <list type="bullet">
    /// <item>
    /// <term>定義位置</term>
    /// <description>
    /// <para>
    /// エンティティビルダをエンティティの内部クラスにすることで、エンティティの private メンバーにエンティティビルダからアクセスすることができます。
    /// エンティティビルダのためだけにメンバーの公開範囲を広くする (internal にする) 必要はありません。
    /// </para>
    /// <code>
    /// partial class Entity
    /// {
    ///     // エンティティビルダをエンティティの内部クラスにする.
    ///     [Serializable]
    ///     public class Builder : EntityBuilder&lt;Entity, IBuildErrorHandler, IConstraintValidator&gt;
    ///     {
    ///     }
    /// }
    /// </code>
    /// </description>
    /// </item>
    /// <item>
    /// <term>コンストラクタとプロパティ</term>
    /// <description>
    /// <para>
    /// エンティティビルダが扱う構築には、作成と編集の二種類があります。
    /// エンティティビルダはエンティティのプロパティの設定によって構築を行います。
    /// エンティティのコンストラクタは基本的にパラメータを持ちません。
    /// これにより、ビルダによる作成と編集が共通のロジックで行えます。
    /// </para>
    /// <para>
    /// エンティティビルダには、エンティティのプロパティに対応するプロパティを定義します。
    /// また、エンティティビルダには、
    /// 作成を目的としてエンティティビルダを生成するためのコンストラクタと、
    /// 編集を目的としてエンティティビルダを生成するためのコンストラクタをそれぞれ定義します。
    /// 編集を目的とするコンストラクタでは、エンティティの各プロパティをエンティティビルダの各プロパティにコピーします。
    /// </para>
    /// <note type="note">
    /// 構築対象ではないプロパティ (例えばエンティティのメソッド実行時にのみ設定されるプロパティ) については、ビルダにプロパティを定義する必要はありません。
    /// </note>
    /// <note type="important">
    /// 場合によっては、エンティティビルダに定義するのはプロパティではなくロジックを持ったメソッドの方が適切なこともあります。
    /// </note>
    /// <code>
    /// partial class Entity
    /// {
    ///     [Serializable]
    ///     public class Builder : EntityBuilder&lt;Entity, IBuildErrorHandler, IConstraintValidator&gt;
    ///     {
    ///         // 作成を目的とするコンストラクタ.
    ///         public Builder(IConstraintValidator validator)
    ///             : base(validator)
    ///         {
    ///         }
    /// 
    ///         // 編集を目的とするコンストラクタ.
    ///         public Builder(Entity target, IConstraintValidator validator)
    ///             : base(target, validator)
    ///         {
    ///             // エンティティの各プロパティをエンティティビルダの各プロパティにコピー.
    ///             Prop1 = Target.Prop1;
    ///             Prop2 = Target.Prop2;
    ///         }
    ///     
    ///         // エンティティのプロパティに対応するプロパティ.
    ///         public string Prop1 { get; set; }
    ///     
    ///         // エンティティのプロパティに対応するプロパティ.
    ///         public string Prop2 { get; set; }
    ///     }
    /// }
    /// </code>
    /// </description>
    /// </item>
    /// <item>
    /// <term>Build メソッド</term>
    /// <description>
    /// <para>
    /// 構築処理は <see cref="IEntityBuilder&lt;TEntity&gt;.Build()"/> メソッドで行います。
    /// このメソッドでは、(エンティティの作成が目的の場合は) エンティティを生成し、エンティティのプロパティの設定を行います。
    /// ただし、<see cref="IEntityBuilder&lt;TEntity&gt;.IsValid"/> プロパティが false の場合は、構築処理を行わずに
    /// <see cref="System.InvalidOperationException"/> をスローする必要があります。
    /// </para>
    /// <code>
    /// public Entity Build()
    /// {
    ///     // IsValid プロパティが false の場合は, 構築処理を行わずに InvalidOperationException をスロー.
    ///     if (!IsValid)
    ///         throw new InvalidOperationException();
    /// 
    ///     // エンティティの作成が目的の場合はエンティティを生成.
    ///     var result = IsForCreation ? new Entity() : Target;
    ///     // エンティティのプロパティの設定.
    ///     result.Prop1 = Prop1;
    ///     result.Prop2 = Prop2;
    ///     
    ///     return result;
    /// }
    /// </code>
    /// </description>
    /// </item>
    /// <item>
    /// <term>エラー</term>
    /// <description>
    /// <para>
    /// エンティティビルダは、ビルド実行前のエラーを許容し、エラーを外部でハンドルできる仕組みを提供します。
    /// そのために、エラーハンドラインターフェイスとエラー通知メソッドを提供します。
    /// </para>
    /// <para>
    /// エラーハンドラインターフェイスは、全体的なエラーハンドラインターフェイスとプロパティ単位のエラーハンドラインターフェイスの二種類があります。
    /// 全体的なエラーハンドラインターフェイスは、プロパティ単位のエラーハンドラインターフェイスを全て継承し、固有のメンバーは定義しません。
    /// プロパティ単位のエラーハンドラインターフェイスは、プロパティ毎に一つ定義し、そこにエラー種別毎のハンドラメソッドを定義します。
    /// </para>
    /// <code>
    /// partial class Entity
    /// {
    ///     // プロパティ単位のエラーハンドラインターフェイス.
    ///     public interface IProp1ErrorHandler
    ///     {
    ///         void HandleProp1EmptyError();
    ///         void HandleProp1TooLongError();
    ///     }
    /// 
    ///     // プロパティ単位のエラーハンドラインターフェイス.
    ///     public interface IProp2ErrorHandler
    ///     {
    ///         void HandleProp2TooLongError();
    ///     }
    /// 
    ///     // 全体的なエラーハンドラインターフェイス.
    ///     public interface IBuildErrorHandler : 
    ///         // プロパティ単位のエラーハンドラインターフェイスを全て継承.
    ///         IProp1ErrorHandler,
    ///         IProp2ErrorHandler
    ///     {
    ///         // 固有のメンバーは定義しない.
    ///     }
    /// }
    /// </code>
    /// <para>
    /// エラー通知メソッドは、全体的なエラー通知メソッドとプロパティ単位のエラー通知メソッドの二種類があります。
    /// 全体的なエラー通知メソッドは、全体的なエラーハンドラを引数として受け取り、そのエラーハンドラを引数として全てのプロパティ単位のエラー通知メソッドを呼び出します。
    /// プロパティ単位のエラー通知メソッドは、対応するプロパティ単位のエラーハンドラを引数として受け取り、そのエラーハンドラに各種エラーを通知します。
    /// </para>
    /// <code>
    /// // 全体的なエラー通知メソッド.
    /// public override void NotifyErrorTo(IBuildErrorHandler handler)
    /// {
    ///     if (handler == null)
    ///         throw new ArgumentNullException("handler");
    ///         
    ///     // 全体的なエラーハンドラを引数として受け取り,
    ///     // そのエラーハンドラを引数として全てのプロパティ単位のエラー通知メソッドを呼び出す.
    ///     NotifyProp1ErrorTo(handler);
    ///     NotifyProp2ErrorTo(handler);
    /// }
    /// 
    /// // プロパティ単位のエラー通知メソッド.
    /// public void NotifyProp1ErrorTo(IProp1ErrorHandler handler)
    /// {
    ///     if (handler == null)
    ///         throw new ArgumentNullException("handler");
    ///         
    ///     // 対応するプロパティ単位のエラーハンドラを引数として受け取り,
    ///     // そのエラーハンドラに各種エラーを通知.
    ///     if (string.IsNullOrWhiteSpace(Prop1))
    ///     {
    ///         handler.HandleProp1EmptyError();
    ///     }
    ///     if ((Prop1 != null) &amp;&amp; (Prop1MaxLength &lt; Prop1.Length))
    ///     {
    ///         handler.HandleProp1TooLongError();
    ///     }
    /// }
    /// 
    /// // Prop1 の最大長.
    /// // 上位レイヤで利用できるようパブリックにする.
    /// public static readonly int Prop1MaxLength = 100;
    /// 
    /// // プロパティ単位のエラー通知メソッド.
    /// public void NotifyProp2ErrorTo(IProp2ErrorHandler handler)
    /// {
    ///     if (handler == null)
    ///         throw new ArgumentNullException("handler");
    ///     
    ///     // 対応するプロパティ単位のエラーハンドラを引数として受け取り,
    ///     // そのエラーハンドラに各種エラーを通知.
    ///     if (string.IsNullOrWhiteSpace(Prop2))
    ///     {
    ///         handler.HandleProp2EmptyError();
    ///     }
    /// }
    /// </code>
    /// </description>
    /// </item>
    /// <item>
    /// <term>制約検証</term>
    /// <description>
    /// <para>
    /// 一意制約が適用されるプロパティがある場合、ビルダで制約検証をする必要があります。
    /// 一意制約が適用されるプロパティがない場合、このクラスの代わりに <see cref="EntityBuilder&lt;TEntity, TErrorHandler&gt;"/> クラスを基本クラスとすることができます。
    /// </para>
    /// <para>
    /// 通常、制約検証はデータストアへのアクセスを伴うため、ドメインレイヤでは制約検証を抽象化したインターフェイスのみを提供し、
    /// 上位レイヤでこれを実装することになります。
    /// エンティティビルダはエラー通知メソッドで制約検証を行い、制約違反があればエラーとして通知します。
    /// </para>
    /// <code>
    /// partial class Entity
    /// {
    ///     // 制約検証インターフェイス.
    ///     public interface IConstraintValidator
    ///     {
    ///         // Prop3 が一意であることを検証するメソッド.
    ///         bool Prop3IsUnique(string prop3);
    ///     }
    /// 
    ///     // Prop3 のエラーハンドラインターフェイス
    ///     public interface IProp3ErrorHandler
    ///     {
    ///         // 未入力エラー.
    ///         void HandleProp3EmptyError();
    ///         
    ///         // 重複エラー.
    ///         void HandleProp3DuplicationError();
    ///     }
    ///     
    ///     [Serializable]
    ///     public class Builder : EntityBuilder&lt;Entity, IBuildErrorHandler, IConstraintValidator&gt;
    ///     {
    ///         // Prop3 のエラー通知メソッド.
    ///         public void NotifyProp3ErrorTo(IIdErrorHandler handler)
    ///         {
    ///             if (handler == null)
    ///                 throw new ArgumentNullException("handler");
    ///         
    ///             if (string.IsNullOrWhiteSpace(Prop3))
    ///             {
    ///                 handler.HandleProp3EmptyError();
    ///             }
    ///             // 作成目的の場合, または編集目的で Prop3 が変更されている場合は一意制約検証を行う.
    ///             if ((IsForCreation) || (!string.Equals(Target.Prop3, Prop3, StringComparison.OrdinalIgnoreCase)))
    ///             {
    ///                 // Prop3 の一意制約を検証.
    ///                 if ((Prop3 != null) &amp;&amp; (!Validator.Prop3IsUnique(Prop3)))
    ///                 {
    ///                     handler.HandleProp3DuplicationError();
    ///                 }
    ///             }
    ///         }
    ///     }
    /// }
    /// </code>
    /// </description>
    /// </item>
    /// <item>
    /// <term>関連するエンティティ</term>
    /// <description>
    /// <para>
    /// 集約内の子エンティティがある場合、子エンティティについても同様にビルダを用意し、
    /// ルートエンティティのビルダには子エンティティのビルダを取得・設定するプロパティを定義します。
    /// また、子エンティティのビルダのコンストラクタの可視性はインターナルとし、
    /// ルートエンティティのビルダには子エンティティのビルダを生成するメソッドを定義します。
    /// </para>
    /// <note type="important">
    /// 子エンティティのビルダを取得・設定するプロパティを定義する場合、
    /// 子エンティティのビルダがエラーを含んでいないか、ルートエンティティのビルダで検証する必要があります。
    /// </note>
    /// <note type="important">
    /// 制約検証インターフェイスは、エンティティ毎に定義するのではなく集約内で一つだけ定義するようにします。
    /// </note>
    /// <para>
    /// 集約外のエンティティを取得・設定するプロパティについては、ビルダではなくエンティティを直接扱うプロパティを定義します。
    /// </para>
    /// <note type="important">
    /// 集約外のエンティティと相互参照している場合は、必要に応じて集約外のエンティティの操作を行い整合を取ります。
    /// </note>
    /// <code>
    /// [Serializable]
    /// public class Builder : EntityBuilder&lt;Root, IBuildErrorHandler, IConstraintValidator&gt;
    /// {
    ///     public Builder(IConstraintValidator validator)
    ///         : base(validator)
    ///     {
    ///         ChildBuilders = new List&lt;Child.Builder&gt;();
    ///     }
    /// 
    ///     public Builder(Root target, IConstraintValidator validator)
    ///         : base(target, validator)
    ///     {
    ///         // 集約内の子エンティティについては, 子エンティティのビルダを生成してフィールドに保持.
    ///         _childBuilders = Target.Children.Select(child => new Child.Builder(child, Validator)).ToList();
    ///         // 集約外のエンティティについては, 直接フィールドに保持.
    ///         Other = Target.Other;
    ///     }
    ///     
    ///     // 集約内の子エンティティについてはビルダを扱う.
    ///     private readonly List&lt;Child.Builder&gt; _childBuilders;
    ///     public List&lt;Child.Builder&gt; ChildBuilders
    ///     {
    ///         get
    ///         {
    ///             return _childBuilders;
    ///         }
    ///     }
    ///     
    ///     // 集約外のエンティティについてはビルダではなくエンティティを直接扱う.
    ///     public Other Other { get; set; };
    ///     
    /// 
    ///     // 子エンティティのビルダの生成メソッドを提供する.
    ///     public Child.Builder CreateChildBuilder()
    ///     {
    ///         return new Child.Builder(Validator);
    ///     }
    /// 
    ///     public void NotifyErrorTo(IBuildErrorHandler handler)
    ///     {
    ///         if (handler == null)
    ///         {
    ///             throw new ArgumentNullException("handler");
    ///         }
    /// 
    ///         NotifyMemostErrorTo(handler);
    ///     }
    /// 
    ///     public void NotifyMemosErrorTo(IChildrenErrorHandler handler)
    ///     {
    ///         if (handler == null)
    ///         {
    ///             throw new ArgumentNullException("handler");
    ///         }
    /// 
    ///         // 子エンティティのビルダがエラーを含んでいないか検証.
    ///         foreach (var childBuilder in _childBuilders)
    ///         {
    ///             if (!childBuilder.IsValid)
    ///             {
    ///                 handler.HandleChildrenErrorContainingError();
    ///                 break;
    ///             }
    ///         }
    ///     }
    /// 
    /// 
    ///     public Root Build()
    ///     {
    ///         if (!IsValid)
    ///         {
    ///             throw new InvalidOperationException();
    ///         }
    /// 
    ///         var result = IsForCreation ? new Root() : Target;
    /// 
    ///         // 子エンティティのリストを一度クリアする.
    ///         result.Children.Clear();
    ///         foreach (var childBuilder in _childBuilders)
    ///         {
    ///             // 子エンティティをビルドしてリストに追加.
    ///             var child = childBuilder.Build();
    ///             result.Children.Add(child);
    ///         }
    /// 
    ///         // 集約外のエンティティを設定.
    ///         // 相互参照している場合は, 必要に応じて集約外のエンティティの操作を行い整合を取る.
    ///         result.Category = Category;
    /// 
    ///         return result;
    ///     }
    /// }
    /// </code>
    /// </description>
    /// </item>
    /// </list>
    /// </remarks>
    /// <example>
    /// エンティティビルダによって構築されるエンティティの実装方法を次のコード例に示します。
    /// <code>
    /// using System;
    /// using System.Collections.Generic;
    /// using System.Collections.ObjectModel;
    /// using MoroMoro.Samples.ToDoList.Domain.Categories;
    /// 
    /// namespace MoroMoro.Samples.ToDoList.Domain.ToDos
    /// {
    ///     [Serializable]
    ///     public sealed partial class ToDo
    ///     {
    ///         private ToDo()
    ///         {
    ///             Memos = new List&lt;Memo&gt;();
    ///             RegisteredDateTime = DateTime.Now; // 構築対象でない且つ生成時に値が決まる特性を持つプロパティ.
    ///         }
    /// 
    /// 
    ///         public string Title
    ///         {
    ///             get;
    ///             private set;
    ///         }
    /// 
    ///         public Category Category
    ///         {
    ///             get;
    ///             private set;
    ///         }
    /// 
    ///         internal IList&lt;Memo&gt; Memos
    ///         {
    ///             get;
    ///             private set;
    ///         }
    /// 
    ///         public DateTime RegisteredDateTime
    ///         {
    ///             get;
    ///             private set;
    ///         }
    /// 
    ///         public DateTime? TouchedDateTime
    ///         {
    ///             get;
    ///             private set;
    ///         }
    /// 
    ///         public DateTime? CompletedDateTime
    ///         {
    ///             get;
    ///             private set;
    ///         }
    /// 
    ///         public ReadOnlyCollection&lt;Memo&gt; GetMemos()
    ///         {
    ///             return new ReadOnlyCollection&lt;Memo&gt;(Memos);
    ///         }
    ///     }
    /// }
    /// </code>
    /// エラーハンドラインターフェイスの定義方法を次のコード例に示します。
    /// <code>
    /// using System;
    /// 
    /// namespace MoroMoro.Samples.ToDoList.Domain.ToDos
    /// {
    ///     partial class ToDo
    ///     {
    ///         public interface ITitleErrorHandler
    ///         {
    ///             void HandleTitleEmptyError();
    /// 
    ///             void HandleTitleTooLongError();
    ///             
    ///             void HandleTitleDuplicationError();
    ///         }
    /// 
    ///         public interface IMemosErrorHandler
    ///         {
    ///             void HandleMemosTooManyError();
    /// 
    ///             void HandleMemosErrorContainingError();
    ///         }
    /// 
    ///         public interface IBuildErrorHandler : 
    ///             ITitleErrorHandler, 
    ///             IMemosErrorHandler
    ///         {
    ///         }
    ///     }
    /// }
    /// </code>
    /// 制約検証インターフェイスの定義方法を次のコード例に示します。
    /// <code>
    /// using System;
    /// 
    /// namespace MoroMoro.Samples.ToDoList.Domain.ToDos
    /// {
    ///     partial class ToDo
    ///     {
    ///         public interface IConstraintValidator
    ///         {
    ///             bool TitleIsUnique(string title);
    ///         }
    ///     }
    /// }
    /// </code>
    /// エンティティビルダの実装方法を次のコード例に示します。
    /// <code>
    /// using System;
    /// using System.Collections.Generic;
    /// using System.Linq;
    /// using MoroMoro.Samples.ToDoList.Base.Domain.Builders;
    /// using MoroMoro.Samples.ToDoList.Domain.Categories;
    /// 
    /// namespace MoroMoro.Samples.ToDoList.Domain.ToDos
    /// {
    ///     partial class ToDo
    ///     {
    ///         [Serializable]
    ///         public sealed class Builder : EntityBuilder&lt;ToDo, IBuildErrorHandler, IConstraintValidator&gt;
    ///         {
    ///             public static readonly int TitleMaxLength = 100;
    /// 
    ///             public static readonly int MemosMaxCount = 5;
    /// 
    /// 
    ///             public Builder(IConstraintValidator validator)
    ///                 : base(validator)
    ///             {
    ///                 _memoBuilders = new List&lt;Memo.Builder&gt;();
    ///             }
    /// 
    ///             public Builder(ToDo target, IConstraintValidator validator)
    ///                 : base(target, validator)
    ///             {
    ///                 _memoBuilders = Target.Memos.Select(memo => new Memo.Builder(memo)).ToList();
    ///                 Title = Target.Title;
    ///                 Category = Target.Category;
    ///             }
    /// 
    /// 
    ///             private readonly List&lt;Memo.Builder&gt; _memoBuilders;
    /// 
    /// 
    ///             public string Title
    ///             {
    ///                 get;
    ///                 set;
    ///             }
    /// 
    ///             public Category Category
    ///             {
    ///                 get;
    ///                 set;
    ///             }
    /// 
    ///             public List&lt;Memo.Builder&gt; MemoBuilders
    ///             {
    ///                 get
    ///                 {
    ///                     return _memoBuilders;
    ///                 }
    ///             }
    /// 
    /// 
    ///             public Memo.Builder CreateMemoBuilder()
    ///             {
    ///                 return new Memo.Builder();
    ///             }
    ///             
    /// 
    ///             public override void NotifyErrorTo(IBuildErrorHandler handler)
    ///             {
    ///                 if (handler == null)
    ///                 {
    ///                     throw new ArgumentNullException("handler");
    ///                 }
    /// 
    ///                 NotifyTitleErrorTo(handler);
    ///                 NotifyMemosErrorTo(handler);
    ///             }
    /// 
    ///             public void NotifyTitleErrorTo(ITitleErrorHandler handler)
    ///             {
    ///                 if (handler == null)
    ///                 {
    ///                     throw new ArgumentNullException("handler");
    ///                 }
    /// 
    ///                 if (string.IsNullOrWhiteSpace(Title))
    ///                 {
    ///                     handler.HandleTitleEmptyError();
    ///                 }
    ///                 if ((Title != null) &amp;&amp; (TitleMaxLength &lt; Title.Length))
    ///                 {
    ///                     handler.HandleTitleTooLongError();
    ///                 }
    ///                 if (IsForCreation || (!string.Equals(Target.Title, Title, StringComparison.OrdinalIgnoreCase)))
    ///                 {
    ///                     if ((Title != null) &amp;&amp; (!Validator.TitleIsUnique(Title)))
    ///                     {
    ///                         handler.HandleTitleDuplicationError();
    ///                     }
    ///                 }
    ///             }
    /// 
    ///             public void NotifyMemosErrorTo(IMemosErrorHandler handler)
    ///             {
    ///                 if (handler == null)
    ///                 {
    ///                     throw new ArgumentNullException("handler");
    ///                 }
    /// 
    ///                 if (MemosMaxCount &lt; _memoBuilders.Count())
    ///                 {
    ///                     handler.HandleMemosTooManyError();
    ///                 }
    ///                 foreach (var memoBuilder in _memoBuilders)
    ///                 {
    ///                     if (!memoBuilder.IsValid)
    ///                     {
    ///                         handler.HandleMemosErrorContainingError();
    ///                         break;
    ///                     }
    ///                 }
    ///             }
    /// 
    /// 
    ///             public override ToDo Build()
    ///             {
    ///                 if (!IsValid)
    ///                 {
    ///                     throw new InvalidOperationException();
    ///                 }
    /// 
    ///                 var result = IsForCreation ? new ToDo() : Target;
    /// 
    ///                 result.Title = Title;
    /// 
    ///                 if (result.Category != Category)
    ///                 {
    ///                     if (result.Category != null)
    ///                     {
    ///                         result.Category.ToDos.Remove(result);
    ///                     }
    /// 
    ///                     result.Category = Category;
    /// 
    ///                     if (Category != null)
    ///                     {
    ///                         Category.ToDos.Add(result);
    ///                     }
    ///                 }
    /// 
    ///                 result.Memos.Clear();
    ///                 foreach (var memoBuilder in _memoBuilders)
    ///                 {
    ///                     result.Memos.Add(memoBuilder.Build());
    ///                 }
    /// 
    ///                 return result;
    ///             }
    ///         }
    ///     }
    /// }
    /// </code>
    /// </example>
    /// <typeparam name="TEntity">エンティティの型。</typeparam>
    /// <typeparam name="TErrorHandler">エラーハンドラの型。</typeparam>
    /// <typeparam name="TConstraintValidator">制約検証オブジェクトの型。</typeparam>
    /// <seealso cref="IEntityBuilder&lt;TEntity&gt;"/>
    /// <seealso cref="EntityBuilder&lt;TEntity, TErrorHandler&gt;"/>
    [Serializable]
    public abstract class EntityBuilder<TEntity, TErrorHandler, TConstraintValidator> : EntityBuilder<TEntity, TErrorHandler>
        where TEntity : class
        where TErrorHandler : class
        where TConstraintValidator : class
    {
        /// <summary>
        /// エンティティの作成を目的として、<see cref="EntityBuilder&lt;TEntity, TErrorHandler, TConstraintValidator&gt;"/> クラスの新しいインスタンスを初期化します。
        /// </summary>
        /// <param name="validator">制約検証オブジェクト。</param>
        /// <exception cref="System.ArgumentNullException">validator が null です。</exception>
        public EntityBuilder(TConstraintValidator validator)
            : base()
        {
            if (validator == null)
            {
                throw new ArgumentNullException("valdator");
            }
            _validator = validator;
        }

        /// <summary>
        /// エンティティの編集を目的として、<see cref="EntityBuilder&lt;TEntity, TErrorHandler, TConstraintValidator&gt;"/> クラスの新しいインスタンスを初期化します。
        /// </summary>
        /// <param name="target">編集対象のエンティティ。</param>
        /// <param name="validator">制約検証オブジェクト。</param>
        /// <exception cref="System.ArgumentNullException">target または validator が null です。</exception>
        public EntityBuilder(TEntity target, TConstraintValidator validator)
            : base(target)
        {
            if (validator == null)
            {
                throw new ArgumentNullException("valdator");
            }
            _validator = validator;
        }


        /// <summary>
        /// 制約検証オブジェクト。
        /// </summary>
        private readonly TConstraintValidator _validator;


        /// <summary>
        /// 制約検証オブジェクトを取得します。
        /// </summary>
        protected TConstraintValidator Validator
        {
            get
            {
                return _validator;
            }
        }
    }
}
